]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
layout: Trigger the message tray by downward pressure
authorJasper St. Pierre <jstpierre@mecheye.net>
Mon, 30 Jul 2012 19:25:07 +0000 (16:25 -0300)
committerJasper St. Pierre <jstpierre@mecheye.net>
Fri, 8 Feb 2013 19:28:11 +0000 (14:28 -0500)
A pressure barrier is a barrier that activates after the user pushes
against the bottom of the screen in a short time. Implement this using
the new XInput 2.3 features that provide extended information about
pointer barriers, and use it so that pushing against the bottom of
the screen edge brings up the message tray.

https://bugzilla.gnome.org/show_bug.cgi?id=677215

js/ui/layout.js
js/ui/messageTray.js

index 09e14fe6d986459aab01127da31b825fcaab3561..2d99c44272da11b98c625e90db51c489e5196fa8 100644 (file)
@@ -19,6 +19,11 @@ const STARTUP_ANIMATION_TIME = 0.2;
 const KEYBOARD_ANIMATION_TIME = 0.15;
 const PLYMOUTH_TRANSITION_TIME = 1;
 
+// The message tray takes this much pressure
+// in the pressure barrier at once to release it.
+const MESSAGE_TRAY_PRESSURE_THRESHOLD = 200; // pixels
+const MESSAGE_TRAY_PRESSURE_TIMEOUT = 3000; // ms
+
 const MonitorConstraint = new Lang.Class({
     Name: 'MonitorConstraint',
     Extends: Clutter.Constraint,
@@ -114,6 +119,7 @@ const LayoutManager = new Lang.Class({
         this._background = null;
         this._leftPanelBarrier = null;
         this._rightPanelBarrier = null;
+        this._trayBarrier = null;
 
         this._inOverview = false;
         this._updateRegionIdle = 0;
@@ -313,9 +319,34 @@ const LayoutManager = new Lang.Class({
         }
     },
 
+    _updateTrayBarrier: function() {
+        let monitor = this.bottomMonitor;
+
+        if (this._trayBarrier) {
+            this._trayBarrier.destroy();
+            this._trayPressure = null;
+        }
+
+        if (this._trayPressure) {
+            this._trayPressure.destroy();
+            this._trayPressure = null;
+        }
+
+        this._trayBarrier = new Meta.Barrier({ display: global.display,
+                                               x1: monitor.x, x2: monitor.x + monitor.width,
+                                               y1: monitor.y + monitor.height, y2: monitor.y + monitor.height,
+                                               directions: Meta.BarrierDirection.NEGATIVE_Y });
+
+        this._trayPressure = new PressureBarrier(this._trayBarrier, MESSAGE_TRAY_PRESSURE_THRESHOLD, MESSAGE_TRAY_PRESSURE_TIMEOUT);
+        this._trayPressure.connect('trigger', function(barrier) {
+            Main.messageTray.openTray();
+        });
+    },
+
     _monitorsChanged: function() {
         this._updateMonitors();
         this._updateBoxes();
+        this._updateTrayBarrier();
         this._updateHotCorners();
         this._updateFullscreen();
         this._updateVisibility();
@@ -1052,3 +1083,107 @@ const HotCorner = new Lang.Class({
         return false;
     }
 });
+
+const PressureBarrier = new Lang.Class({
+    Name: 'PressureBarrier',
+
+    _init: function(barrier, threshold, timeout) {
+        this._barrier = barrier;
+        this._threshold = threshold;
+        this._timeout = timeout;
+        this._orientation = (barrier.y1 == barrier.y2) ? Clutter.Orientation.HORIZONTAL : Clutter.Orientation.VERTICAL;
+
+        this._reset();
+
+        this._barrierHitId = this._barrier.connect('hit', Lang.bind(this, this._onBarrierHit));
+        this._barrierLeftId = this._barrier.connect('left', Lang.bind(this, this._onBarrierLeft));
+    },
+
+    destroy: function() {
+        this._barrier.disconnect(this._barrierHitId);
+        this._barrier.disconnect(this._barrierLeftId);
+        this._barrier = null;
+    },
+
+    _reset: function() {
+        this._barrierEvents = [];
+        this._currentPressure = 0;
+        this._lastTime = 0;
+    },
+
+    _getDistanceAcrossBarrier: function(event) {
+        if (this._orientation == Clutter.Orientation.HORIZONTAL)
+            return Math.abs(event.dy);
+        else
+            return Math.abs(event.dx);
+    },
+
+    _getDistanceAlongBarrier: function(event) {
+        if (this._orientation == Clutter.Orientation.HORIZONTAL)
+            return Math.abs(event.dx);
+        else
+            return Math.abs(event.dy);
+    },
+
+    _isBarrierEventTooOld: function(event) {
+        // Ignore all events older than this time
+        let threshold = this._lastTime - this._timeout;
+        return event.time < threshold;
+    },
+
+    _trimBarrierEvents: function() {
+        // Events are guaranteed to be sorted in time order from
+        // oldest to newest, so just look for the first old event,
+        // and then chop events after that off.
+        let i = 0;
+        while (i < this._barrierEvents.length) {
+            if (!this._isBarrierEventTooOld(this._barrierEvents[i++]))
+                break;
+        }
+
+        let firstNewEvent = i;
+
+        for (i = 0; i < firstNewEvent; i++) {
+            this._currentPressure -= this._getDistanceAcrossBarrier(this._barrierEvents[i]);
+        }
+
+        this._barrierEvents = this._barrierEvents.slice(firstNewEvent);
+    },
+
+    _addBarrierEvent: function(event) {
+        this._barrierEvents.push(event);
+        this._currentPressure += this._getDistanceAcrossBarrier(event);
+    },
+
+    _onBarrierLeft: function(barrier, event) {
+        this._reset();
+    },
+
+    _onBarrierHit: function(barrier, event) {
+        // Throw out all events where the pointer was grabbed,
+        // as the client that grabbed the pointer expects to have
+        // complete control over it.
+        if (event.grabbed)
+            return;
+
+        let slide = this._getDistanceAlongBarrier(event);
+        let distance = this._getDistanceAcrossBarrier(event);
+
+        // Throw out events where the cursor is move more
+        // along the axis of the barrier than moving with
+        // the barrier.
+        if (slide > distance)
+            return;
+
+        this._lastTime = event.time;
+
+        this._trimBarrierEvents();
+        this._addBarrierEvent(event);
+
+        if (this._currentPressure >= this._threshold) {
+            this.emit('trigger');
+            this._reset();
+        }
+    }
+});
+Signals.addSignalMethods(PressureBarrier.prototype);
index 457fc772a6cbeb043cdc0c821fdf0749271ef774..b9eec1745f8f3dc0fd5869810c0fabf91bc830b2 100644 (file)
@@ -1706,10 +1706,13 @@ const MessageTray = new Lang.Class({
         if (currentUserTime != this._trayDwellUserTime)
             return false;
 
+        this.openTray();
+        return false;
+    },
+
+    openTray: function() {
         this._traySummoned = true;
         this._updateState();
-
-        return false;
     },
 
     _onNotificationKeyRelease: function(actor, event) {